'''
Created on Nov 3, 2009

@author: wangjo
'''
from google.appengine.ext import db
from google.appengine.ext.db import polymodel
from google.appengine.api import memcache
import logging
import datetime
import spider
import utility

DEFAULT_OFFSET = 50
PER_CRAWLER_COUNT = 5

class model(db.Model):
    username = db.StringProperty(required = True)
    homepage = db.LinkProperty(required = True)
    name = db.StringProperty()
    name_cn = db.StringProperty()
    name_en = db.StringProperty()
    status = db.StringProperty(multiline = True)
    gender = db.BooleanProperty() #true as male, false 
    mtg = db.BooleanProperty(default = False) #true as male, false 
    category = db.StringListProperty()  #like actor, model, hostness etc
    birthdate = db.StringProperty()
    excluded = db.BooleanProperty(default = False)
    count_album_total = db.IntegerProperty()
    astrology = db.StringProperty()
    address = db.StringProperty()
    age = db.StringProperty()
    visitcount = db.IntegerProperty()
    avatar = db.LinkProperty()
    hometown = db.StringProperty()
    height = db.StringProperty()
    weight = db.StringProperty()
    size = db.StringProperty()
    level = db.IntegerProperty()
    blood = db.StringProperty()
    fair = db.StringProperty()
    feet = db.StringProperty()
    iphone = db.BooleanProperty(default=False)
    iphonefree = db.BooleanProperty(default=False)
    checked = db.BooleanProperty(default = False) #true as male, false 
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def add_model(username, url):
        if not username: return
        username = username.strip()
        m = db.Query(model).filter('username =', username).get()
        if m: return
        m = model(username = username, homepage=db.Link(url))
        m.put()
        
    @staticmethod
    def _get_model():
        return db.Query(model).filter('gender =', False)
        
    @staticmethod
    def get_models(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        q = model._get_model()
        return q.order('username').fetch(limit, offset)
        
    @staticmethod
    def get_model_count():
        q = model._get_model()
        return q.count()
    
    @staticmethod
    def _get_topgirl():
        return db.Query(model).filter('mtg =', True)
    
    @staticmethod 
    def get_topgirls(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        q = model._get_topgirl()
        return q.order('created').fetch(limit, offset)
    
    @staticmethod
    def get_topgirl_count():
        q = model._get_topgirl()
        return q.count()
    
    @staticmethod
    def _get_topgirl_iphone():
        return db.Query(model).filter('mtg =', True).filter('iphone =', True)
    
    @staticmethod 
    def get_topgirls_iphone(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        q = model._get_topgirl_iphone()
        return q.order('-visitcount').fetch(limit, offset)
    
    @staticmethod
    def get_topgirl_iphone_count():
        q = model._get_topgirl_iphone()
        return q.count()
    
    @staticmethod
    def get_model(username):
        if not username: return None
        return db.Query(model).filter('username =', username).get()
    
    def get_photo_count(self):
        #return db.Query(photo).filter('model =', self).filter('album !=', None).count()
        return db.Query(photo).filter('model =', self).count()
    
    #get the photo count in original moko site static values
    def get_moko_photo_count(self):
        result = 0
        albums = self.get_albums()
        if albums:
            for a in albums:
                if a.count_photo:
                    result += a.count_photo 
        return result
    
    @staticmethod
    def add_topgirl(username, m):
        if not username: return
        username = username.strip()
        t = db.Query(model).filter('username =', username).get()
        if not t:
            t = model(username = username, homepage = m.homepage)
        t.name = m.name
        t.category = m.category
        t.gender = False
        t.birthdate = m.birthdate
        t.astrology = m.astrology
        t.avatar = m.avatar
        t.address = m.address
        t.age = m.age
        t.visitcount = m.visitcount
        t.put()
        return t
    
    @staticmethod 
    def get_topgirls_from(limit, lastkey = None):
        q = db.Query(model).filter('gender =', False).order('username')
        if lastkey:
            m = model.get(lastkey)
            if m:
                q.filter('username >', m.username)
        return q.fetch(limit)
            
    def get_photos(self):
        return db.Query(photo).filter('model =', self).fetch(1000)
    
    def get_album_count(self):
        return db.Query(album).filter('model =', self).count()
    
    def get_albums(self, limit = 1000, offset = 0):
        return db.Query(album).filter('model =', self).fetch(limit, offset)
    
    def get_albums_unfiltered(self, limit = 1000, offset = 0):
        return db.Query(album).filter('model =', self).filter('filtered !=', True).fetch(limit, offset)
    
    def _get_album_iphone(self):
        return db.Query(album).filter('model =', self).filter('iphone =', True)
    
    def get_album_iphone_count(self):
        q = self._get_album_iphone()
        return q.count()
    
    def get_albums_iphone(self, limit = 1000, offset = 0):
        q = self._get_album_iphone()
        return q.order('-count_visit').fetch(limit, offset)
    
    def get_avatar_photos(self, limit = 1000, offset = 0):
        return db.Query(photo).filter('model =', self).filter('tag =', spider.TAG_AVATAR).order('-created').fetch(limit, offset)
    
class cronlog(polymodel.PolyModel):
    _ACTION_CRON = 'cron'
    _ACTION_LOOPMODEL = 'loop-model'
    _ACTION_FILTER = 'filter'
    _ACTION_DOWNLOAD = 'download'
    _ACTION_VERIFY = 'verify'
    _ACTION_SIZE = 'size'
    _ACTION_UPDATEURL = 'url'
    
    action = db.StringProperty()
    content = db.StringProperty()
    target = db.StringProperty()
    successed = db.BooleanProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def get_useless_logs(count):
        if not count:
            count = DEFAULT_OFFSET*10
        t = datetime.timedelta(20)
        return db.Query(cronlog).filter('created <', datetime.datetime.now() - t).order('created').fetch(count)
    
    @staticmethod
    def get_non_crawled_models(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_LOOPMODEL).filter('successed =', True).order('-created')
        log = q.get()
        if log:
            parsedCount = int(log.target)
            logging.info('current count:%d'%parsedCount)
            totalModelCount = model.get_model_count()
            logging.info('total model count:%d'%totalModelCount)
            if parsedCount < totalModelCount:
                m = model.get_model(log.content)
                if m:
                    #still some models need to be crawlered
                    return db.Query(model).filter('created >', m.created).filter('gender =', False).order('created').fetch(count)
                else:
                    return db.Query(model).filter('gender =', False).order('created').fetch(count)
            else:
                #restart
                return db.Query(model).filter('gender =', False).order('created').fetch(count)
        else:
            return db.Query(model).filter('gender =', False).order('created').fetch(count)
        
    @staticmethod
    def get_non_filtered_models(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_FILTER).filter('successed =', True).order('-created')
        log = q.get()
        if log:
            parsedCount = int(log.target)
            logging.info('current count:%d'%parsedCount)
            totalModelCount = model.get_model_count()
            logging.info('total model count:%d'%totalModelCount)
            if parsedCount < totalModelCount:
                m = model.get_model(log.content)
                if m:
                    #still some models need to be crawlered
                    return db.Query(model).filter('created >', m.created).filter('gender =', False).order('created').fetch(count)
                else:
                    return db.Query(model).filter('gender =', False).order('created').fetch(count)
            else:
                #restart
                logging.warn("Filter model has finished")
                #return None
                return db.Query(model).filter('gender =', False).order('created').fetch(count)
        else:
            return db.Query(model).filter('gender =', False).order('created').fetch(count)
        
    @staticmethod
    def add_filter_model(username, successed):
        m = model.get_model(username)
        if m:
            index = db.Query(model).filter('created <', m.created).filter('gender =', False).count(1000)
            l = cronlog(action=cronlog._ACTION_FILTER, content =username, target=str(index+1), successed=successed)
            l.put()
        else:
            logging.error('the try to added username:[%s] does not exist in datastore'%username)
            
    @staticmethod
    def add_crawler_model(username, successed):
        m = model.get_model(username)
        if m:
            index = db.Query(model).filter('created <', m.created).filter('gender =', False).count(1000)
            l = cronlog(action=cronlog._ACTION_LOOPMODEL, content =username, target=str(index+1), successed=successed)
            l.put()
        else:
            logging.error('the try to added username:[%s] does not exist in datastore'%username)
            
    @staticmethod  
    def get_non_crawled_albums(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_CRON).filter('target =', 'album').filter('successed =', True).order('-created')
        a = q.get()
        if a:
            s = db.Query(album).filter('url =', a.content).get()
            return db.Query(album).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(album).order('created').fetch(count)
    
    @staticmethod
    def add_crawler_album(url, successed):
        l = cronlog(action=cronlog._ACTION_CRON, content =url, target='album', successed=successed)
        l.put()
        
    @staticmethod  
    def get_non_downloaded_photos(limit, offset):
        if not limit:
            limit = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_DOWNLOAD).filter('target =', 'photo').filter('successed =', True).order('-created')
        a = q.get()
        if a:
            s = db.Query(photo).filter('url =', a.content).get()
            return db.Query(photo).filter('created >', s.created).order('created').fetch(limit, offset)
        else:  
            return db.Query(photo).order('created').fetch(limit, offset)
    
    @staticmethod
    def add_download_photo(imagekey, successed):
        p = photo.get(imagekey)
        if p:
            l = cronlog(action=cronlog._ACTION_DOWNLOAD, content = p.url, target='photo', successed=successed)
            l.put()
            return p
        else:
            logging.debug('add download photo log has error with key: %s'%imagekey)
            return None
        
    @staticmethod  
    def get_non_crawled_gallery(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_CRON).filter('target =', 'gallery').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(model).filter('username =', m.content).get()
            return db.Query(model).filter('gender =', False).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(model).filter('gender =', False).order('created').fetch(count)
    
    @staticmethod
    def get_non_sized_photos(count):
        if not count:
            count = PER_CRAWLER_COUNT
        return db.Query(photo).filter('width <', 0).fetch(count)
        
    @staticmethod
    def add_crawler_gallery(username, successed):
        l = cronlog(action=cronlog._ACTION_CRON, content = username, target='gallery', successed=successed)
        l.put()
    
    @staticmethod
    def add_verify_album(album, successed):
        l = cronlog(action=cronlog._ACTION_VERIFY, content = album.url, target='album', successed=successed)
        l.put()  

    @staticmethod
    def add_sized_photo(photo, successed):
        l = cronlog(action=cronlog._ACTION_SIZE, content = photo.url, target='photo', successed=successed)
        l.put()  
        
    @staticmethod 
    def get_non_verified_albums(count):
        if not count:
            count = PER_CRAWLER_COUNT*4 #20
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_VERIFY).filter('target =', 'album').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(album).filter('url =', m.content).get()
            return db.Query(album).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(album).order('created').fetch(count)  
    
    @staticmethod    
    def get_non_updated_photos(count):
        if not count:
            count = PER_CRAWLER_COUNT*40 #200
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_UPDATEURL).filter('target =', 'photo').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = photo.get_by_id(int(m.content))
            result = db.Query(photo).filter('created >', s.created).order('created').fetch(int(count))
            if len(result) == 0:
                logging.warning('updated for photo url cron has completed')
                utility.sendmail('updated for photo url cron has completed', 'you can remove this cron task now')
            return result
        else:
            return db.Query(photo).order('created').fetch(count)
    
    @staticmethod
    def get_non_updated_avatars(count):
        if not count:
            count = PER_CRAWLER_COUNT*4 #20
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_UPDATEURL).filter('target =', 'avatar').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = model.get_by_id(int(m.content))
            result = db.Query(model).filter('created >', s.created).order('created').fetch(int(count))
            if len(result) == 0:
                logging.warning('updated for avatar cron has completed')
                utility.sendmail('updated for avatar cron has completed', 'you can remove this cron task now')
            return result
        else:
            return db.Query(model).order('created').fetch(count)
    
    @staticmethod
    def get_non_updated_albums(count):
        if not count:
            count = PER_CRAWLER_COUNT*20 #20
        q = db.Query(cronlog).filter('action =', cronlog._ACTION_UPDATEURL).filter('target =', 'album').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = album.get_by_id(int(m.content))
            result = db.Query(album).filter('created >', s.created).order('created').fetch(int(count))
            if len(result) == 0:
                logging.warning('updated for album cover url cron has completed')
                utility.sendmail('updated for album cover url cron has completed', 'you can remove this cron task now')
            return result
        else:
            return db.Query(album).order('created').fetch(count)
    
    @staticmethod
    def add_updated_photo(photo):
        if not photo: return False
        l = cronlog(action= cronlog._ACTION_UPDATEURL, content = str(photo.key().id()), target ='photo', successed=True)
        l.put()
        return True
    
    @staticmethod
    def add_updated_avatar(model):
        if not model: return False
        l = cronlog(action= cronlog._ACTION_UPDATEURL, content = str(model.key().id()), target ='avatar', successed=True)
        l.put()
        return True
    @staticmethod
    def add_updated_album(album):
        if not model: return False
        l = cronlog(action= cronlog._ACTION_UPDATEURL, content = str(album.key().id()), target ='album', successed=True)
        l.put()
        return True
        
class album(db.Model):
    model = db.ReferenceProperty(model, required = True)
    title = db.StringProperty()
    url = db.LinkProperty(required = True)
    count_photo = db.IntegerProperty()
    count_visit = db.IntegerProperty()
    count_comment = db.IntegerProperty() 
    albumdate = db.StringProperty()
    mtgalbum = db.BooleanProperty(default = False)
    selected = db.BooleanProperty(default = False)
    excluded = db.BooleanProperty(default = False)
    cover = db.LinkProperty()
    iphone = db.BooleanProperty(default=False)
    filtered = db.BooleanProperty(default = False)
    downloaded = db.BooleanProperty(default=False)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    def get_photos(self, limit = 1000, offset = 0):
        return db.Query(photo).filter('album =', self).filter('url !=', self.cover).fetch(limit, offset)
    
    def get_filtering_photos(self, limit = 1000, offset = 0):
        return db.Query(photo).filter('album =', self).order('-created').fetch(limit, offset)
    
    def get_photos_iphone_count(self):
        return db.Query(photo).filter('album =', self).filter('iphone =', True).count()
    
    def get_photos_iphone(self, limit = 1000, offset = 0):
        return db.Query(photo).filter('album =', self).filter('iphone =', True).order('created').fetch(limit, offset)
    
    def get_photo_count(self):
        return db.Query(photo).filter('album =', self).filter('url !=', self.cover).count() # ignore the cover
    
    def deletable(self):
        result = False
        if self.url:
            splits = self.url.split('/')
            htmlName = splits[len(splits)-1]
            existAlbums = db.Query(album).filter('model =', self.model).filter('url !=', self.url).fetch(1000)
            if existAlbums:
                for a in existAlbums:
                    if a.url:
                        items = a.url.split('/')
                        targetHtmlName = items[len(items)-1]
                        if htmlName.lower() == targetHtmlName.lower():
                            result = True
                            break
        return result
    
    @staticmethod
    def add_album(model, url, title, count_photo, count_visit, count_comment, albumdate, cover):
        if not model: return
        if not url: return
        m = None
        # check if already exists an album in database with different url
        splits = url.split('/')
        if len(splits) >0:
            htmlName = splits[len(splits)-1]
            existAlbums = db.Query(album).filter('model =', model).fetch(1000)
            if existAlbums:
                for a in existAlbums:
                    if a.url:
                        items = a.url.split('/')
                        targetHtmlName = items[len(items)-1]
                        if htmlName.lower() == targetHtmlName.lower():
                            m = a
                            break
        if not m:
            q = db.Query(album).filter('model =', model).filter('url =', url)
            m = q.get()
            if not m:
                m = album(model = model, url = db.Link(url))
        m.title = title
        m.count_photo = int(count_photo)
        m.count_visit = int(count_visit)
        m.count_comment = int(count_comment)
        m.albumdate = albumdate
        m.cover = db.Link(cover)
        m.put()
        return m

    @staticmethod 
    def get_albums(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        return db.Query(album).order('created').fetch(limit, offset)
    
    @staticmethod
    def get_album_count():
        return db.Query(album).count()
    
    @staticmethod
    def get_album_by_url(albumurl):
        if not albumurl: return None
        return db.Query(album).filter('url =', albumurl).get()
   
class rawphotodata(db.Model):
    rawdata = db.BlobProperty()
    url = db.LinkProperty()
    ptype = db.StringProperty()
    model = db.ReferenceProperty(model)
    when = db.DateTimeProperty(auto_now_add=True)
    lastupdated = db.DateTimeProperty(auto_now=True)
    
    @staticmethod
    def get_rawphoto(url, model=None):
        if not url: return None
        q = db.Query(rawphotodata)
        if model:
            q.filter('model =', model)
        return q.filter('url =', url).get()
            
    @staticmethod
    def add_avatar_photo(url, blob, model):
        if not url: return None
        if not blob: return None
        if not model: return None
        p = db.Query(rawphotodata).filter('model = ', model).filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url, ptype='avatar', model = model)
        else:
            p.ptype = 'avatar'
            p.rawdata = blob
        
        p.put()
        return p
        
    @staticmethod
    def add_model_photo(url, blob, model):
        if not url: return None
        if not blob: return None
        if not model: return None
        p = db.Query(rawphotodata).filter('model = ', model).filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url, ptype='model', model = model)
        else:
            p.ptype = 'model'
            p.rawdata = blob
        
        p.put()  
        return p
    
    @staticmethod
    def add_common_photo(url, blob, model = None):
        if not url: return None
        if not blob: return None
        q = db.Query(rawphotodata)
        if model:
            q.filter('model =', model)
        p = q.filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url)
        else:
            p.rawdata = blob
        if model:
            p.model = model
            p.ptype = 'model'
        else:
            p.ptype = 'common'
        
        p.put()  
        return p  
    
class category(db.Model):
    title = db.StringProperty(required = True)
    name_cn = db.StringProperty()
    name_en = db.StringProperty()
    name_jp = db.StringProperty()
    name_tw = db.StringProperty()
    desc = db.StringProperty()
    avatar = db.LinkProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def add_categories(categories):
        return False
    
    @staticmethod
    def add_category(title):
        if not title: return None
        q = db.Query(category).filter('title =', title).get()
        if not q:
            q = category(title = title)
            q.put()
        return q
    
    @staticmethod
    def get_categories(limit = 1000, offset=0):
        return db.Query(category).order('created').fetch(int(limit), int(offset))
    
    @staticmethod
    def get_category_count():
        return db.Query(category).count()
    
    def get_model_count(self):
        return db.Query(category_model).filter('category =', self).count()
    
    def get_iphone_model_count(self):
        cache = memcache.Client()
        key = "count_%s"%self.key();
        count = cache.get(str(key), utility.CACHE_NS_CATEGORY)
        if not count:
            relations = db.Query(category_model).filter('category =', self).fetch(1000)
            count = 0
            if relations:
                for modelcat in relations:
                    if modelcat.model.mtg and modelcat.model.iphone:
                        count = count+1
            cache.set(str(key), count, time=utility.CACHE_DURATION, namespace = utility.CACHE_NS_CATEGORY)
        
        return int(count)
    
    def get_models(self, limit, offset = 0):
        relations = db.Query(category_model).filter('category =', self).order('created').fetch(int(limit), int(offset))
        result = []
        if relations:
            for rel in relations:
                result.append(rel.model)
        return result
    
    def get_iphone_models(self, limit, offset = 0):
        relations = db.Query(category_model).filter('category =', self).order('created').fetch(1000)
        result = []
        index = 0
        if relations:
            for rel in relations:
                if rel.model.mtg and rel.model.iphone:
                    if index >= offset:
                        result.append(rel.model)
                    index = index+1
                if len(result) == limit:
                    break
        return result         
    
class category_model(db.Model):
    category = db.ReferenceProperty(category, required = True)
    model = db.ReferenceProperty(model, required = True)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    
    @staticmethod
    def bind_model_category(model):
        if model.category:
            q = db.Query(category_model).filter('model =', model).fetch(20, 0)
            if len(q) == len(model.category):
                return True
            for item in model.category:
                #add item into categories:
                c = category.add_category(item)
                if q:
                    existed = False
                    for cat in q:
                        if cat.category.title == c.title:
                            existed = True
                    if not existed:
                        r = category_model(category = c, model = model)
                        r.put()
                else:
                    r = category_model(category = c, model = model)
                    r.put()
        return True 
    
    @staticmethod
    def get_model_categories(model):
        if not model: return None
        return db.Query(category_model).filter('model =', model)   
    
class photo(db.Model):
    title = db.StringProperty()
    url = db.LinkProperty(required = True)
    width = db.IntegerProperty()
    height = db.IntegerProperty()
    album = db.ReferenceProperty(album)
    model = db.ReferenceProperty(model)
    comment = db.TextProperty()
    tag = db.StringProperty()
    iphone = db.BooleanProperty(default=True)
    downloaded = db.BooleanProperty(default=False)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def add_photo(url, model, album = None, title = None, comment = None, tag = None):
        if not url: return
        if not model: return
        p = db.Query(photo).filter('model =', model).filter('url =', url).get()
        if not p:
            p = photo(title = title, url = url, album = album, model = model, comment = comment, tag = tag)
            p.put()
        else:
            p.album = album
            if title:
                p.title = title
            p.tag = tag
            p.put()
        return p
    @staticmethod
    def get_photo_by_url(url):
        if not url: return None
        return db.Query(photo).filter('url =', url).get()
    
    @staticmethod
    def reload_photo(photo):
        db.run_in_transaction(reload_transcation, photo)

def reload_transcation(oldPhoto):
    p = photo(title = oldPhoto.title, url = oldPhoto.url, album = oldPhoto.album, model = oldPhoto.model)
    p.put()
    oldPhoto.delete()

class setting(db.Model):
    name = db.StringProperty(required=True)
    value = db.StringProperty(required=True)
    type = db.StringProperty(required=True, choices=set(["bool", "int", "float", "string"]))
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    
    @staticmethod
    def _add_setting(name, value, type, update=False):
        q = db.Query(setting).filter('name =', name)
        s = q.fetch()
        if s:
            if update:
                s.value = value
                s.type = type
            else:
                logging.error('the specified setting [%s] has already existed'%name)
                return False
        else:
            s = setting(name = name, value = value, type = type)
        s.put()
        return True
    
    @staticmethod
    def get_setting(name):
        result = None
        if not name:
            return result
        q = db.Query(setting).filter('name =', name)
        s = q.get()
        if not s:
            return result
        if s.type == 'bool':
            result = bool(s.value)
        elif s.type == 'int':
            result = int(s.value)
        elif s.type == 'float':
            result = float(s.value)
        else:
            result = s.value
        return result
            
    @staticmethod
    def add_setting_bool(name, value):
        bVal = bool(value)
        type = 'bool'
        setting._add_setting(name, str(bVal), type)
    
    @staticmethod
    def add_setting_int(name, value):
        intVal = int(value)
        type = 'int'
        setting._add_setting(name, intVal, type)
        
    @staticmethod
    def add_setting_float(name, value):
        floatVal = float(value)
        type = 'float'
        setting._add_setting(name, floatVal, type)
    
    @staticmethod
    def add_setting_string(name, value):
        strVal = str(value)
        type = 'string'
        setting._add_setting(name, strVal, type) 
     